//                           _       _
// __      _____  __ ___   ___  __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
//  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
//   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
//
//  Copyright © 2016 - 2025 Weaviate B.V. All rights reserved.
//
//  CONTACT: hello@weaviate.io
//

package types

import (
	"github.com/weaviate/weaviate/entities/models"
)

const UsageDiskVersion int = 1

// UsageDisk defines format of saved pre-computed shard usage data
type UsageDisk struct {
	// Version of the
	Version int `json:"version"`
	// ShardUsage
	ShardUsage *ShardUsage `json:"shardUsage"`
}

// Report represents the usage metrics report from the metrics endpoint
type Report struct {
	// The version of usage policy, current weaviate version
	// e.g. 1.32.0, otherwise it will default to a date based versioning
	Version string `json:"version,omitempty"`

	// The name of the node
	Node string `json:"node,omitempty"`

	// List of collections and their metrics
	Collections CollectionsUsage `json:"collections,omitempty"`

	// List of backups and their metrics
	Backups []*BackupUsage `json:"backups,omitempty"`

	// CollectingTime The time of the collection of the metric
	CollectingTime string `json:"-"`

	// The local node's view of the schema
	Schema *models.Schema `json:"schema,omitempty"`

	GoMemLimit int64 `json:"go_mem_limit,omitempty"`
}

// CollectionUsage represents metrics for a single collection
type CollectionUsage struct {
	// The name of the collection
	Name string `json:"name,omitempty"`

	// The replication factor of the collection
	ReplicationFactor int `json:"replication_factor,omitempty"`

	// The number of unique shards in the collection
	UniqueShardCount int `json:"unique_shard_count,omitempty"`

	// List of shards and their metrics
	Shards ShardsUsage `json:"shards,omitempty"`
}

// ShardUsage represents metrics for a single shard
type ShardUsage struct {
	// The name of the shard
	Name string `json:"name,omitempty"`

	// The status of the shard (ACTIVE, INACTIVE)
	Status string `json:"status,omitempty"`

	// The number of objects in the shard
	ObjectsCount int64 `json:"objects_count"`

	// The disk storage used by objects in bytes
	ObjectsStorageBytes uint64 `json:"objects_storage_bytes"`

	// The disk storage used by vectors in bytes
	VectorStorageBytes uint64 `json:"vector_storage_bytes"`

	// The disk storage used by indices in bytes
	IndexStorageBytes uint64 `json:"index_storage_bytes"`

	// The disk storage used by the full shard in bytes (objects + vectors + indices + hnsw commitlogs)
	FullShardStorageBytes uint64 `json:"full_shard_storage_bytes"`

	// List of named vectors and their metrics
	NamedVectors VectorsUsage `json:"named_vectors,omitempty"`
}

// VectorUsage represents metrics for a single vector index
type VectorUsage struct {
	// The name of the vector
	Name string `json:"name"`

	// The type of vector index (for dynamic indexes, this shows the underlying type: flat/hnsw)
	VectorIndexType string `json:"vector_index_type,omitempty"`

	// Indicates if this index originated from a dynamic index configuration
	IsDynamic bool `json:"is_dynamic,omitempty"`

	// The compression type used
	Compression string `json:"compression,omitempty"`

	// The compression ratio achieved
	VectorCompressionRatio float64 `json:"vector_compression_ratio,omitempty"`

	// The bits parameter for RQ compression (only set when Compression="rq")
	Bits int16 `json:"bits,omitempty"`

	// List of dimensionalities and their metrics. Note: List is not needed here, but we keep it like this for the consumer
	Dimensionalities []*Dimensionality `json:"dimensionalities,omitempty"`

	// Configuration for Multi-Vector
	MultiVectorConfig *MultiVectorConfig `json:"multi_vector_config,omitempty"`
}

type MultiVectorConfig struct {
	Enabled      bool          `json:"enabled"`
	MuveraConfig *MuveraConfig `json:"muvera_config,omitempty"`
}

type MuveraConfig struct {
	Enabled      bool `json:"enabled"`
	KSim         int  `json:"ksim"`
	DProjections int  `json:"dprojections"`
	Repetitions  int  `json:"repetitions"`
}

// Dimensionality represents metrics for a specific dimensionality
type Dimensionality struct {
	// The dimensionality of the vectors
	Dimensions int `json:"dimensionality,omitempty"`

	// The number of objects with this dimensionality
	Count int `json:"count,omitempty"`
}

// BackupUsage represents metrics for a single backup
type BackupUsage struct {
	// The ID of the backup
	ID string `json:"id,omitempty"`

	// The completion time of the backup
	CompletionTime string `json:"completion_time,omitempty"`

	// The size of the backup in GiB
	SizeInGib float64 `json:"size_in_gib,omitempty"`

	// The type of backup
	Type string `json:"type,omitempty"`

	// The list of collections included in the backup
	Collections []string `json:"collections,omitempty"`
}

type ObjectUsage struct {
	Count        int64
	StorageBytes int64
}

// ByCollectionName implements sort.Interface for []*CollectionUsage based on the Name field.
type CollectionsUsage []*CollectionUsage

func (a CollectionsUsage) Len() int      { return len(a) }
func (a CollectionsUsage) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a CollectionsUsage) Less(i, j int) bool {
	if a[i] == nil && a[j] == nil {
		return false
	}
	if a[i] == nil {
		return true
	}
	if a[j] == nil {
		return false
	}
	return a[i].Name < a[j].Name
}

type ShardsUsage []*ShardUsage

func (a ShardsUsage) Len() int      { return len(a) }
func (a ShardsUsage) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ShardsUsage) Less(i, j int) bool {
	if a[i] == nil && a[j] == nil {
		return false
	}
	if a[i] == nil {
		return true
	}
	if a[j] == nil {
		return false
	}
	return a[i].Name < a[j].Name
}

type VectorsUsage []*VectorUsage

func (a VectorsUsage) Len() int      { return len(a) }
func (a VectorsUsage) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a VectorsUsage) Less(i, j int) bool {
	if a[i] == nil && a[j] == nil {
		return false
	}
	if a[i] == nil {
		return true
	}
	if a[j] == nil {
		return false
	}
	return a[i].Name < a[j].Name
}
